1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package sun.awt;
27
28 import java.awt.Font;
29 import java.io.DataInputStream;
30 import java.io.DataOutputStream;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.InputStream;
34 import java.io.IOException;
35 import java.io.OutputStream;
36 import java.nio.charset.Charset;
37 import java.nio.charset.CharsetEncoder;
38 import java.security.AccessController;
39 import java.security.PrivilegedAction;
40 import java.util.Arrays;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.Hashtable;
44 import java.util.Locale;
45 import java.util.Map.Entry;
46 import java.util.Properties;
47 import java.util.Set;
48 import java.util.Vector;
49 import sun.font.CompositeFontDescriptor;
50 import sun.font.SunFontManager;
51 import sun.font.FontManagerFactory;
52 import sun.font.FontUtilities;
53 import sun.util.logging.PlatformLogger;
54
55
56
57
58
59
60 public abstract class FontConfiguration {
61
62
63 protected static String osVersion;
64 protected static String osName;
65 protected static String encoding;
66 protected static Locale startupLocale = null;
67 protected static Hashtable localeMap = null;
68 private static FontConfiguration fontConfig;
69 private static PlatformLogger logger;
70 protected static boolean isProperties = true;
71
72 protected SunFontManager fontManager;
73 protected boolean preferLocaleFonts;
74 protected boolean preferPropFonts;
75
76 private File fontConfigFile;
77 private boolean foundOsSpecificFile;
78 private boolean inited;
79 private String javaLib;
80
81
82
83
84 public FontConfiguration(SunFontManager fm) {
85 if (FontUtilities.debugFonts()) {
86 FontUtilities.getLogger()
87 .info("Creating standard Font Configuration");
88 }
89 if (FontUtilities.debugFonts() && logger == null) {
90 logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
91 }
92 fontManager = fm;
93 setOsNameAndVersion();
94 setEncoding();
95
96
97
98
99 findFontConfigFile();
100 }
101
102 public synchronized boolean init() {
103 if (!inited) {
104 this.preferLocaleFonts = false;
105 this.preferPropFonts = false;
106 setFontConfiguration();
107 readFontConfigFile(fontConfigFile);
108 initFontConfig();
109 inited = true;
110 }
111 return true;
112 }
113
114 public FontConfiguration(SunFontManager fm,
115 boolean preferLocaleFonts,
116 boolean preferPropFonts) {
117 fontManager = fm;
118 if (FontUtilities.debugFonts()) {
119 FontUtilities.getLogger()
120 .info("Creating alternate Font Configuration");
121 }
122 this.preferLocaleFonts = preferLocaleFonts;
123 this.preferPropFonts = preferPropFonts;
124
125
126
127
128 initFontConfig();
129 }
130
131
132
133
134
135
136 protected void setOsNameAndVersion() {
137 osName = System.getProperty("os.name");
138 osVersion = System.getProperty("os.version");
139 }
140
141 private void setEncoding() {
142 encoding = Charset.defaultCharset().name();
143 startupLocale = SunToolkit.getStartupLocale();
144 }
145
146
147
148
149
150 public boolean foundOsSpecificFile() {
151 return foundOsSpecificFile;
152 }
153
154
155
156
157 public boolean fontFilesArePresent() {
158 init();
159 short fontNameID = compFontNameIDs[0][0][0];
160 short fileNameID = getComponentFileID(fontNameID);
161 final String fileName = mapFileName(getComponentFileName(fileNameID));
162 Boolean exists = (Boolean)java.security.AccessController.doPrivileged(
163 new java.security.PrivilegedAction() {
164 public Object run() {
165 try {
166 File f = new File(fileName);
167 return Boolean.valueOf(f.exists());
168 }
169 catch (Exception e) {
170 return false;
171 }
172 }
173 });
174 return exists.booleanValue();
175 }
176
177 private void findFontConfigFile() {
178
179 foundOsSpecificFile = true;
180 String javaHome = System.getProperty("java.home");
181 if (javaHome == null) {
182 throw new Error("java.home property not set");
183 }
184 javaLib = javaHome + File.separator + "lib";
185 String userConfigFile = System.getProperty("sun.awt.fontconfig");
186 if (userConfigFile != null) {
187 fontConfigFile = new File(userConfigFile);
188 } else {
189 fontConfigFile = findFontConfigFile(javaLib);
190 }
191 }
192
193 private void readFontConfigFile(File f) {
194
195
196
197
198
199 getInstalledFallbackFonts(javaLib);
200
201 if (f != null) {
202 try {
203 FileInputStream in = new FileInputStream(f.getPath());
204 if (isProperties) {
205 loadProperties(in);
206 } else {
207 loadBinary(in);
208 }
209 in.close();
210 if (FontUtilities.debugFonts()) {
211 logger.config("Read logical font configuration from " + f);
212 }
213 } catch (IOException e) {
214 if (FontUtilities.debugFonts()) {
215 logger.config("Failed to read logical font configuration from " + f);
216 }
217 }
218 }
219 String version = getVersion();
220 if (!"1".equals(version) && FontUtilities.debugFonts()) {
221 logger.config("Unsupported fontconfig version: " + version);
222 }
223 }
224
225 protected void getInstalledFallbackFonts(String javaLib) {
226 String fallbackDirName = javaLib + File.separator +
227 "fonts" + File.separator + "fallback";
228
229 File fallbackDir = new File(fallbackDirName);
230 if (fallbackDir.exists() && fallbackDir.isDirectory()) {
231 String[] ttfs = fallbackDir.list(fontManager.getTrueTypeFilter());
232 String[] t1s = fallbackDir.list(fontManager.getType1Filter());
233 int numTTFs = (ttfs == null) ? 0 : ttfs.length;
234 int numT1s = (t1s == null) ? 0 : t1s.length;
235 int len = numTTFs + numT1s;
236 if (numTTFs + numT1s == 0) {
237 return;
238 }
239 installedFallbackFontFiles = new String[len];
240 for (int i=0; i<numTTFs; i++) {
241 installedFallbackFontFiles[i] =
242 fallbackDir + File.separator + ttfs[i];
243 }
244 for (int i=0; i<numT1s; i++) {
245 installedFallbackFontFiles[i+numTTFs] =
246 fallbackDir + File.separator + t1s[i];
247 }
248 fontManager.registerFontsInDir(fallbackDirName);
249 }
250 }
251
252 private File findImpl(String fname) {
253 File f = new File(fname + ".properties");
254 if (f.canRead()) {
255 isProperties = true;
256 return f;
257 }
258 f = new File(fname + ".bfc");
259 if (f.canRead()) {
260 isProperties = false;
261 return f;
262 }
263 return null;
264 }
265
266 private File findFontConfigFile(String javaLib) {
267 String baseName = javaLib + File.separator + "fontconfig";
268 File configFile;
269 if (osVersion != null && osName != null) {
270 configFile = findImpl(baseName + "." + osName + "." + osVersion);
271 if (configFile != null) {
272 return configFile;
273 }
274 }
275 if (osName != null) {
276 configFile = findImpl(baseName + "." + osName);
277 if (configFile != null) {
278 return configFile;
279 }
280 }
281 if (osVersion != null) {
282 configFile = findImpl(baseName + "." + osVersion);
283 if (configFile != null) {
284 return configFile;
285 }
286 }
287 foundOsSpecificFile = false;
288
289 configFile = findImpl(baseName);
290 if (configFile != null) {
291 return configFile;
292 }
293 return null;
294 }
295
296
297
298
299 public static void loadBinary(InputStream inStream) throws IOException {
300 DataInputStream in = new DataInputStream(inStream);
301 head = readShortTable(in, HEAD_LENGTH);
302 int[] tableSizes = new int[INDEX_TABLEEND];
303 for (int i = 0; i < INDEX_TABLEEND; i++) {
304 tableSizes[i] = head[i + 1] - head[i];
305 }
306 table_scriptIDs = readShortTable(in, tableSizes[INDEX_scriptIDs]);
307 table_scriptFonts = readShortTable(in, tableSizes[INDEX_scriptFonts]);
308 table_elcIDs = readShortTable(in, tableSizes[INDEX_elcIDs]);
309 table_sequences = readShortTable(in, tableSizes[INDEX_sequences]);
310 table_fontfileNameIDs = readShortTable(in, tableSizes[INDEX_fontfileNameIDs]);
311 table_componentFontNameIDs = readShortTable(in, tableSizes[INDEX_componentFontNameIDs]);
312 table_filenames = readShortTable(in, tableSizes[INDEX_filenames]);
313 table_awtfontpaths = readShortTable(in, tableSizes[INDEX_awtfontpaths]);
314 table_exclusions = readShortTable(in, tableSizes[INDEX_exclusions]);
315 table_proportionals = readShortTable(in, tableSizes[INDEX_proportionals]);
316 table_scriptFontsMotif = readShortTable(in, tableSizes[INDEX_scriptFontsMotif]);
317 table_alphabeticSuffix = readShortTable(in, tableSizes[INDEX_alphabeticSuffix]);
318 table_stringIDs = readShortTable(in, tableSizes[INDEX_stringIDs]);
319
320
321 stringCache = new String[table_stringIDs.length + 1];
322
323 int len = tableSizes[INDEX_stringTable];
324 byte[] bb = new byte[len * 2];
325 table_stringTable = new char[len];
326 in.read(bb);
327 int i = 0, j = 0;
328 while (i < len) {
329 table_stringTable[i++] = (char)(bb[j++] << 8 | (bb[j++] & 0xff));
330 }
331 if (verbose) {
332 dump();
333 }
334 }
335
336
337
338
339 public static void saveBinary(OutputStream out) throws IOException {
340 sanityCheck();
341
342 DataOutputStream dataOut = new DataOutputStream(out);
343 writeShortTable(dataOut, head);
344 writeShortTable(dataOut, table_scriptIDs);
345 writeShortTable(dataOut, table_scriptFonts);
346 writeShortTable(dataOut, table_elcIDs);
347 writeShortTable(dataOut, table_sequences);
348 writeShortTable(dataOut, table_fontfileNameIDs);
349 writeShortTable(dataOut, table_componentFontNameIDs);
350 writeShortTable(dataOut, table_filenames);
351 writeShortTable(dataOut, table_awtfontpaths);
352 writeShortTable(dataOut, table_exclusions);
353 writeShortTable(dataOut, table_proportionals);
354 writeShortTable(dataOut, table_scriptFontsMotif);
355 writeShortTable(dataOut, table_alphabeticSuffix);
356 writeShortTable(dataOut, table_stringIDs);
357
358 dataOut.writeChars(new String(table_stringTable));
359 out.close();
360 if (verbose) {
361 dump();
362 }
363 }
364
365
366 private static short stringIDNum;
367 private static short[] stringIDs;
368 private static StringBuilder stringTable;
369
370 public static void loadProperties(InputStream in) throws IOException {
371
372
373 stringIDNum = 1;
374 stringIDs = new short[1000];
375 stringTable = new StringBuilder(4096);
376
377 if (verbose && logger == null) {
378 logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
379 }
380 new PropertiesHandler().load(in);
381
382
383 stringIDs = null;
384 stringTable = null;
385 }
386
387
388
389
390
391
392
393
394
395
396 private void initFontConfig() {
397 initLocale = startupLocale;
398 initEncoding = encoding;
399 if (preferLocaleFonts && !willReorderForStartupLocale()) {
400 preferLocaleFonts = false;
401 }
402 initELC = getInitELC();
403 initAllComponentFonts();
404 }
405
406
407
408
409
410 private short getInitELC() {
411 if (initELC != -1) {
412 return initELC;
413 }
414 HashMap <String, Integer> elcIDs = new HashMap<String, Integer>();
415 for (int i = 0; i < table_elcIDs.length; i++) {
416 elcIDs.put(getString(table_elcIDs[i]), i);
417 }
418 String language = initLocale.getLanguage();
419 String country = initLocale.getCountry();
420 String elc;
421 if (elcIDs.containsKey(elc=initEncoding + "." + language + "." + country)
422 || elcIDs.containsKey(elc=initEncoding + "." + language)
423 || elcIDs.containsKey(elc=initEncoding)) {
424 initELC = elcIDs.get(elc).shortValue();
425 } else {
426 initELC = elcIDs.get("NULL.NULL.NULL").shortValue();
427 }
428 int i = 0;
429 while (i < table_alphabeticSuffix.length) {
430 if (initELC == table_alphabeticSuffix[i]) {
431 alphabeticSuffix = getString(table_alphabeticSuffix[i + 1]);
432 return initELC;
433 }
434 i += 2;
435 }
436 return initELC;
437 }
438
439 public static boolean verbose;
440 private short initELC = -1;
441 private Locale initLocale;
442 private String initEncoding;
443 private String alphabeticSuffix;
444
445 private short[][][] compFontNameIDs = new short[NUM_FONTS][NUM_STYLES][];
446 private int[][][] compExclusions = new int[NUM_FONTS][][];
447 private int[] compCoreNum = new int[NUM_FONTS];
448
449 private Set<Short> coreFontNameIDs = new HashSet<Short>();
450 private Set<Short> fallbackFontNameIDs = new HashSet<Short>();
451
452 private void initAllComponentFonts() {
453 short[] fallbackScripts = getFallbackScripts();
454 for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
455 short[] coreScripts = getCoreScripts(fontIndex);
456 compCoreNum[fontIndex] = coreScripts.length;
457
458
459
460
461
462
463
464 int[][] exclusions = new int[coreScripts.length][];
465 for (int i = 0; i < coreScripts.length; i++) {
466 exclusions[i] = getExclusionRanges(coreScripts[i]);
467 }
468 compExclusions[fontIndex] = exclusions;
469
470 for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
471 int index;
472 short[] nameIDs = new short[coreScripts.length + fallbackScripts.length];
473
474 for (index = 0; index < coreScripts.length; index++) {
475 nameIDs[index] = getComponentFontID(coreScripts[index],
476 fontIndex, styleIndex);
477 if (preferLocaleFonts && localeMap != null &&
478 fontManager.usingAlternateFontforJALocales()) {
479 nameIDs[index] = remapLocaleMap(fontIndex, styleIndex,
480 coreScripts[index], nameIDs[index]);
481 }
482 if (preferPropFonts) {
483 nameIDs[index] = remapProportional(fontIndex, nameIDs[index]);
484 }
485
486 coreFontNameIDs.add(nameIDs[index]);
487 }
488
489 for (int i = 0; i < fallbackScripts.length; i++) {
490 short id = getComponentFontID(fallbackScripts[i],
491 fontIndex, styleIndex);
492 if (preferLocaleFonts && localeMap != null &&
493 fontManager.usingAlternateFontforJALocales()) {
494 id = remapLocaleMap(fontIndex, styleIndex, fallbackScripts[i], id);
495 }
496 if (preferPropFonts) {
497 id = remapProportional(fontIndex, id);
498 }
499 if (contains(nameIDs, id, index)) {
500 continue;
501 }
502
503
504
505
506 fallbackFontNameIDs.add(id);
507 nameIDs[index++] = id;
508 }
509 if (index < nameIDs.length) {
510 short[] newNameIDs = new short[index];
511 System.arraycopy(nameIDs, 0, newNameIDs, 0, index);
512 nameIDs = newNameIDs;
513 }
514 compFontNameIDs[fontIndex][styleIndex] = nameIDs;
515 }
516 }
517 }
518
519 private short remapLocaleMap(int fontIndex, int styleIndex, short scriptID, short fontID) {
520 String scriptName = getString(table_scriptIDs[scriptID]);
521
522 String value = (String)localeMap.get(scriptName);
523 if (value == null) {
524 String fontName = fontNames[fontIndex];
525 String styleName = styleNames[styleIndex];
526 value = (String)localeMap.get(fontName + "." + styleName + "." + scriptName);
527 }
528 if (value == null) {
529 return fontID;
530 }
531
532 for (int i = 0; i < table_componentFontNameIDs.length; i++) {
533 String name = getString(table_componentFontNameIDs[i]);
534 if (value.equalsIgnoreCase(name)) {
535 fontID = (short)i;
536 break;
537 }
538 }
539 return fontID;
540 }
541
542 public static boolean hasMonoToPropMap() {
543 return table_proportionals != null && table_proportionals.length != 0;
544 }
545
546 private short remapProportional(int fontIndex, short id) {
547 if (preferPropFonts &&
548 table_proportionals.length != 0 &&
549 fontIndex != 2 &&
550 fontIndex != 4) {
551 int i = 0;
552 while (i < table_proportionals.length) {
553 if (table_proportionals[i] == id) {
554 return table_proportionals[i + 1];
555 }
556 i += 2;
557 }
558 }
559 return id;
560 }
561
562
563
564
565 protected static final int NUM_FONTS = 5;
566 protected static final int NUM_STYLES = 4;
567 protected static final String[] fontNames
568 = {"serif", "sansserif", "monospaced", "dialog", "dialoginput"};
569 protected static final String[] publicFontNames
570 = {Font.SERIF, Font.SANS_SERIF, Font.MONOSPACED, Font.DIALOG,
571 Font.DIALOG_INPUT};
572 protected static final String[] styleNames
573 = {"plain", "bold", "italic", "bolditalic"};
574
575
576
577
578
579 public static boolean isLogicalFontFamilyName(String fontName) {
580 return isLogicalFontFamilyNameLC(fontName.toLowerCase(Locale.ENGLISH));
581 }
582
583
584
585
586
587 public static boolean isLogicalFontFamilyNameLC(String fontName) {
588 for (int i = 0; i < fontNames.length; i++) {
589 if (fontName.equals(fontNames[i])) {
590 return true;
591 }
592 }
593 return false;
594 }
595
596
597
598
599 private static boolean isLogicalFontStyleName(String styleName) {
600 for (int i = 0; i < styleNames.length; i++) {
601 if (styleName.equals(styleNames[i])) {
602 return true;
603 }
604 }
605 return false;
606 }
607
608
609
610
611
612 public static boolean isLogicalFontFaceName(String fontName) {
613 return isLogicalFontFaceNameLC(fontName.toLowerCase(Locale.ENGLISH));
614 }
615
616
617
618
619
620 public static boolean isLogicalFontFaceNameLC(String fontName) {
621 int period = fontName.indexOf('.');
622 if (period >= 0) {
623 String familyName = fontName.substring(0, period);
624 String styleName = fontName.substring(period + 1);
625 return isLogicalFontFamilyName(familyName) &&
626 isLogicalFontStyleName(styleName);
627 } else {
628 return isLogicalFontFamilyName(fontName);
629 }
630 }
631
632 protected static int getFontIndex(String fontName) {
633 return getArrayIndex(fontNames, fontName);
634 }
635
636 protected static int getStyleIndex(String styleName) {
637 return getArrayIndex(styleNames, styleName);
638 }
639
640 private static int getArrayIndex(String[] names, String name) {
641 for (int i = 0; i < names.length; i++) {
642 if (name.equals(names[i])) {
643 return i;
644 }
645 }
646 assert false;
647 return 0;
648 }
649
650 protected static int getStyleIndex(int style) {
651 switch (style) {
652 case Font.PLAIN:
653 return 0;
654 case Font.BOLD:
655 return 1;
656 case Font.ITALIC:
657 return 2;
658 case Font.BOLD | Font.ITALIC:
659 return 3;
660 default:
661 return 0;
662 }
663 }
664
665 protected static String getFontName(int fontIndex) {
666 return fontNames[fontIndex];
667 }
668
669 protected static String getStyleName(int styleIndex) {
670 return styleNames[styleIndex];
671 }
672
673
674
675
676
677
678 public static String getLogicalFontFaceName(String familyName, int style) {
679 assert isLogicalFontFamilyName(familyName);
680 return familyName.toLowerCase(Locale.ENGLISH) + "." + getStyleString(style);
681 }
682
683
684
685
686
687
688 public static String getStyleString(int style) {
689 return getStyleName(getStyleIndex(style));
690 }
691
692
693
694
695
696
697
698 public abstract String getFallbackFamilyName(String fontName, String defaultFallback);
699
700
701
702
703
704
705 protected String getCompatibilityFamilyName(String fontName) {
706 fontName = fontName.toLowerCase(Locale.ENGLISH);
707 if (fontName.equals("timesroman")) {
708 return "serif";
709 } else if (fontName.equals("helvetica")) {
710 return "sansserif";
711 } else if (fontName.equals("courier")) {
712 return "monospaced";
713 }
714 return null;
715 }
716
717 protected static String[] installedFallbackFontFiles = null;
718
719
720
721
722
723 protected String mapFileName(String fileName) {
724 return fileName;
725 }
726
727
728
729
730
731
732
733
734 protected HashMap reorderMap = null;
735
736
737 protected abstract void initReorderMap();
738
739
740
741
742 private void shuffle(String[] seq, int src, int dst) {
743 if (dst >= src) {
744 return;
745 }
746 String tmp = seq[src];
747 for (int i=src; i>dst; i--) {
748 seq[i] = seq[i-1];
749 }
750 seq[dst] = tmp;
751 }
752
753
754
755
756
757 public static boolean willReorderForStartupLocale() {
758 return getReorderSequence() != null;
759 }
760
761 private static Object getReorderSequence() {
762 if (fontConfig.reorderMap == null) {
763 fontConfig.initReorderMap();
764 }
765 HashMap reorderMap = fontConfig.reorderMap;
766
767
768 String language = startupLocale.getLanguage();
769 String country = startupLocale.getCountry();
770 Object val = reorderMap.get(encoding + "." + language + "." + country);
771 if (val == null) {
772 val = reorderMap.get(encoding + "." + language);
773 }
774 if (val == null) {
775 val = reorderMap.get(encoding);
776 }
777 return val;
778 }
779
780
781
782
783
784 private void reorderSequenceForLocale(String[] seq) {
785 Object val = getReorderSequence();
786 if (val instanceof String) {
787 for (int i=0; i< seq.length; i++) {
788 if (seq[i].equals(val)) {
789 shuffle(seq, i, 0);
790 return;
791 }
792 }
793 } else if (val instanceof String[]) {
794 String[] fontLangs = (String[])val;
795 for (int l=0; l<fontLangs.length;l++) {
796 for (int i=0; i<seq.length;i++) {
797 if (seq[i].equals(fontLangs[l])) {
798 shuffle(seq, i, l);
799 }
800 }
801 }
802 }
803 }
804
805 private static Vector splitSequence(String sequence) {
806
807 Vector parts = new Vector();
808 int start = 0;
809 int end;
810 while ((end = sequence.indexOf(',', start)) >= 0) {
811 parts.add(sequence.substring(start, end));
812 start = end + 1;
813 }
814 if (sequence.length() > start) {
815 parts.add(sequence.substring(start, sequence.length()));
816 }
817 return parts;
818 }
819
820 protected String[] split(String sequence) {
821 Vector v = splitSequence(sequence);
822 return (String[])v.toArray(new String[0]);
823 }
824
825
826
827
828 private Hashtable charsetRegistry = new Hashtable(5);
829
830
831
832
833
834
835
836 public FontDescriptor[] getFontDescriptors(String fontName, int style) {
837 assert isLogicalFontFamilyName(fontName);
838 fontName = fontName.toLowerCase(Locale.ENGLISH);
839 int fontIndex = getFontIndex(fontName);
840 int styleIndex = getStyleIndex(style);
841 return getFontDescriptors(fontIndex, styleIndex);
842 }
843 private FontDescriptor[][][] fontDescriptors =
844 new FontDescriptor[NUM_FONTS][NUM_STYLES][];
845
846 private FontDescriptor[] getFontDescriptors(int fontIndex, int styleIndex) {
847 FontDescriptor[] descriptors = fontDescriptors[fontIndex][styleIndex];
848 if (descriptors == null) {
849 descriptors = buildFontDescriptors(fontIndex, styleIndex);
850 fontDescriptors[fontIndex][styleIndex] = descriptors;
851 }
852 return descriptors;
853 }
854
855 private FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {
856 String fontName = fontNames[fontIndex];
857 String styleName = styleNames[styleIndex];
858
859 short[] scriptIDs = getCoreScripts(fontIndex);
860 short[] nameIDs = compFontNameIDs[fontIndex][styleIndex];
861 String[] sequence = new String[scriptIDs.length];
862 String[] names = new String[scriptIDs.length];
863 for (int i = 0; i < sequence.length; i++) {
864 names[i] = getComponentFontName(nameIDs[i]);
865 sequence[i] = getScriptName(scriptIDs[i]);
866 if (alphabeticSuffix != null && "alphabetic".equals(sequence[i])) {
867 sequence[i] = sequence[i] + "/" + alphabeticSuffix;
868 }
869 }
870 int[][] fontExclusionRanges = compExclusions[fontIndex];
871
872 FontDescriptor[] descriptors = new FontDescriptor[names.length];
873
874 for (int i = 0; i < names.length; i++) {
875 String awtFontName;
876 String encoding;
877
878 awtFontName = makeAWTFontName(names[i], sequence[i]);
879
880
881 encoding = getEncoding(names[i], sequence[i]);
882 if (encoding == null) {
883 encoding = "default";
884 }
885 CharsetEncoder enc
886 = getFontCharsetEncoder(encoding.trim(), awtFontName);
887
888
889 int[] exclusionRanges = fontExclusionRanges[i];
890
891
892 descriptors[i] = new FontDescriptor(awtFontName, enc, exclusionRanges);
893 }
894 return descriptors;
895 }
896
897
898
899
900
901 protected String makeAWTFontName(String platformFontName,
902 String characterSubsetName) {
903 return platformFontName;
904 }
905
906
907
908
909
910
911
912 protected abstract String getEncoding(String awtFontName,
913 String characterSubsetName);
914
915 private CharsetEncoder getFontCharsetEncoder(final String charsetName,
916 String fontName) {
917
918 Charset fc = null;
919 if (charsetName.equals("default")) {
920 fc = (Charset) charsetRegistry.get(fontName);
921 } else {
922 fc = (Charset) charsetRegistry.get(charsetName);
923 }
924 if (fc != null) {
925 return fc.newEncoder();
926 }
927
928 if (!charsetName.startsWith("sun.awt.") && !charsetName.equals("default")) {
929 fc = Charset.forName(charsetName);
930 } else {
931 Class fcc = (Class) AccessController.doPrivileged(new PrivilegedAction() {
932 public Object run() {
933 try {
934 return Class.forName(charsetName, true,
935 Thread.currentThread().getContextClassLoader());
936 } catch (ClassNotFoundException e) {
937 }
938 return null;
939 }
940 });
941
942 if (fcc != null) {
943 try {
944 fc = (Charset) fcc.newInstance();
945 } catch (Exception e) {
946 }
947 }
948 }
949 if (fc == null) {
950 fc = getDefaultFontCharset(fontName);
951 }
952
953 if (charsetName.equals("default")){
954 charsetRegistry.put(fontName, fc);
955 } else {
956 charsetRegistry.put(charsetName, fc);
957 }
958 return fc.newEncoder();
959 }
960
961 protected abstract Charset getDefaultFontCharset(
962 String fontName);
963
964
965
966
967
968
969 public HashSet<String> getAWTFontPathSet() {
970 return null;
971 }
972
973
974
975
976
977
978
979
980
981
982
983 public CompositeFontDescriptor[] get2DCompositeFontInfo() {
984 CompositeFontDescriptor[] result =
985 new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
986 String defaultFontFile = fontManager.getDefaultFontFile();
987 String defaultFontFaceName = fontManager.getDefaultFontFaceName();
988
989 for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
990 String fontName = publicFontNames[fontIndex];
991
992
993
994
995
996 int[][] exclusions = compExclusions[fontIndex];
997 int numExclusionRanges = 0;
998 for (int i = 0; i < exclusions.length; i++) {
999 numExclusionRanges += exclusions[i].length;
1000 }
1001 int[] exclusionRanges = new int[numExclusionRanges];
1002 int[] exclusionRangeLimits = new int[exclusions.length];
1003 int exclusionRangeIndex = 0;
1004 int exclusionRangeLimitIndex = 0;
1005 for (int i = 0; i < exclusions.length; i++) {
1006 int[] componentRanges = exclusions[i];
1007 for (int j = 0; j < componentRanges.length; ) {
1008 int value = componentRanges[j];
1009 exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];
1010 exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];
1011 }
1012 exclusionRangeLimits[i] = exclusionRangeIndex;
1013 }
1014
1015 for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
1016 int maxComponentFontCount = compFontNameIDs[fontIndex][styleIndex].length;
1017 boolean sawDefaultFontFile = false;
1018
1019 if (installedFallbackFontFiles != null) {
1020 maxComponentFontCount += installedFallbackFontFiles.length;
1021 }
1022 String faceName = fontName + "." + styleNames[styleIndex];
1023
1024
1025 String[] componentFaceNames = new String[maxComponentFontCount];
1026 String[] componentFileNames = new String[maxComponentFontCount];
1027
1028 int index;
1029 for (index = 0; index < compFontNameIDs[fontIndex][styleIndex].length; index++) {
1030 short fontNameID = compFontNameIDs[fontIndex][styleIndex][index];
1031 short fileNameID = getComponentFileID(fontNameID);
1032 componentFaceNames[index] = getFaceNameFromComponentFontName(getComponentFontName(fontNameID));
1033 componentFileNames[index] = mapFileName(getComponentFileName(fileNameID));
1034 if (componentFileNames[index] == null ||
1035 needToSearchForFile(componentFileNames[index])) {
1036 componentFileNames[index] = getFileNameFromComponentFontName(getComponentFontName(fontNameID));
1037 }
1038 if (!sawDefaultFontFile &&
1039 defaultFontFile.equals(componentFileNames[index])) {
1040 sawDefaultFontFile = true;
1041 }
1042
1043
1044
1045
1046 }
1047
1048
1049 if (!sawDefaultFontFile) {
1050 int len = 0;
1051 if (installedFallbackFontFiles != null) {
1052 len = installedFallbackFontFiles.length;
1053 }
1054 if (index + len == maxComponentFontCount) {
1055 String[] newComponentFaceNames = new String[maxComponentFontCount + 1];
1056 System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);
1057 componentFaceNames = newComponentFaceNames;
1058 String[] newComponentFileNames = new String[maxComponentFontCount + 1];
1059 System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);
1060 componentFileNames = newComponentFileNames;
1061 }
1062 componentFaceNames[index] = defaultFontFaceName;
1063 componentFileNames[index] = defaultFontFile;
1064 index++;
1065 }
1066
1067 if (installedFallbackFontFiles != null) {
1068 for (int ifb=0; ifb<installedFallbackFontFiles.length; ifb++) {
1069 componentFaceNames[index] = null;
1070 componentFileNames[index] = installedFallbackFontFiles[ifb];
1071 index++;
1072 }
1073 }
1074
1075 if (index < maxComponentFontCount) {
1076 String[] newComponentFaceNames = new String[index];
1077 System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);
1078 componentFaceNames = newComponentFaceNames;
1079 String[] newComponentFileNames = new String[index];
1080 System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);
1081 componentFileNames = newComponentFileNames;
1082 }
1083
1084
1085
1086 int[] clippedExclusionRangeLimits = exclusionRangeLimits;
1087 if (index != clippedExclusionRangeLimits.length) {
1088 int len = exclusionRangeLimits.length;
1089 clippedExclusionRangeLimits = new int[index];
1090 System.arraycopy(exclusionRangeLimits, 0, clippedExclusionRangeLimits, 0, len);
1091
1092 for (int i = len; i < index; i++) {
1093 clippedExclusionRangeLimits[i] = exclusionRanges.length;
1094 }
1095 }
1096
1097
1098
1099
1100
1101
1102
1103 result[fontIndex * NUM_STYLES + styleIndex]
1104 = new CompositeFontDescriptor(
1105 faceName,
1106 compCoreNum[fontIndex],
1107 componentFaceNames,
1108 componentFileNames,
1109 exclusionRanges,
1110 clippedExclusionRangeLimits);
1111 }
1112 }
1113 return result;
1114 }
1115
1116 protected abstract String getFaceNameFromComponentFontName(String componentFontName);
1117 protected abstract String getFileNameFromComponentFontName(String componentFontName);
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132 HashMap<String, Boolean> existsMap;
1133 public boolean needToSearchForFile(String fileName) {
1134 if (!FontUtilities.isLinux) {
1135 return false;
1136 } else if (existsMap == null) {
1137 existsMap = new HashMap<String, Boolean>();
1138 }
1139 Boolean exists = existsMap.get(fileName);
1140 if (exists == null) {
1141
1142
1143
1144
1145
1146 getNumberCoreFonts();
1147 if (!coreFontFileNames.contains(fileName)) {
1148 exists = Boolean.TRUE;
1149 } else {
1150 exists = Boolean.valueOf((new File(fileName)).exists());
1151 existsMap.put(fileName, exists);
1152 if (FontUtilities.debugFonts() &&
1153 exists == Boolean.FALSE) {
1154 logger.warning("Couldn't locate font file " + fileName);
1155 }
1156 }
1157 }
1158 return exists == Boolean.FALSE;
1159 }
1160
1161 private int numCoreFonts = -1;
1162 private String[] componentFonts = null;
1163 HashMap <String, String> filenamesMap = new HashMap<String, String>();
1164 HashSet <String> coreFontFileNames = new HashSet<String>();
1165
1166
1167
1168
1169
1170 public int getNumberCoreFonts() {
1171 if (numCoreFonts == -1) {
1172 numCoreFonts = coreFontNameIDs.size();
1173 Short[] emptyShortArray = new Short[0];
1174 Short[] core = coreFontNameIDs.toArray(emptyShortArray);
1175 Short[] fallback = fallbackFontNameIDs.toArray(emptyShortArray);
1176
1177 int numFallbackFonts = 0;
1178 int i;
1179 for (i = 0; i < fallback.length; i++) {
1180 if (coreFontNameIDs.contains(fallback[i])) {
1181 fallback[i] = null;
1182 continue;
1183 }
1184 numFallbackFonts++;
1185 }
1186 componentFonts = new String[numCoreFonts + numFallbackFonts];
1187 String filename = null;
1188 for (i = 0; i < core.length; i++) {
1189 short fontid = core[i];
1190 short fileid = getComponentFileID(fontid);
1191 componentFonts[i] = getComponentFontName(fontid);
1192 String compFileName = getComponentFileName(fileid);
1193 if (compFileName != null) {
1194 coreFontFileNames.add(compFileName);
1195 }
1196 filenamesMap.put(componentFonts[i], mapFileName(compFileName));
1197 }
1198 for (int j = 0; j < fallback.length; j++) {
1199 if (fallback[j] != null) {
1200 short fontid = fallback[j];
1201 short fileid = getComponentFileID(fontid);
1202 componentFonts[i] = getComponentFontName(fontid);
1203 filenamesMap.put(componentFonts[i],
1204 mapFileName(getComponentFileName(fileid)));
1205 i++;
1206 }
1207 }
1208 }
1209 return numCoreFonts;
1210 }
1211
1212
1213
1214
1215
1216 public String[] getPlatformFontNames() {
1217 if (numCoreFonts == -1) {
1218 getNumberCoreFonts();
1219 }
1220 return componentFonts;
1221 }
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231 public String getFileNameFromPlatformName(String platformName) {
1232
1233
1234
1235
1236
1237 return filenamesMap.get(platformName);
1238 }
1239
1240
1241
1242
1243
1244 public String getExtraFontPath() {
1245 return getString(head[INDEX_appendedfontpath]);
1246 }
1247
1248 public String getVersion() {
1249 return getString(head[INDEX_version]);
1250 }
1251
1252
1253 protected static FontConfiguration getFontConfiguration() {
1254 return fontConfig;
1255 }
1256
1257 protected void setFontConfiguration() {
1258 fontConfig = this;
1259 }
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319 private static final int HEAD_LENGTH = 20;
1320 private static final int INDEX_scriptIDs = 0;
1321 private static final int INDEX_scriptFonts = 1;
1322 private static final int INDEX_elcIDs = 2;
1323 private static final int INDEX_sequences = 3;
1324 private static final int INDEX_fontfileNameIDs = 4;
1325 private static final int INDEX_componentFontNameIDs = 5;
1326 private static final int INDEX_filenames = 6;
1327 private static final int INDEX_awtfontpaths = 7;
1328 private static final int INDEX_exclusions = 8;
1329 private static final int INDEX_proportionals = 9;
1330 private static final int INDEX_scriptFontsMotif = 10;
1331 private static final int INDEX_alphabeticSuffix = 11;
1332 private static final int INDEX_stringIDs = 12;
1333 private static final int INDEX_stringTable = 13;
1334 private static final int INDEX_TABLEEND = 14;
1335 private static final int INDEX_fallbackScripts = 15;
1336 private static final int INDEX_appendedfontpath = 16;
1337 private static final int INDEX_version = 17;
1338
1339 private static short[] head;
1340 private static short[] table_scriptIDs;
1341 private static short[] table_scriptFonts;
1342 private static short[] table_elcIDs;
1343 private static short[] table_sequences;
1344 private static short[] table_fontfileNameIDs;
1345 private static short[] table_componentFontNameIDs;
1346 private static short[] table_filenames;
1347 protected static short[] table_awtfontpaths;
1348 private static short[] table_exclusions;
1349 private static short[] table_proportionals;
1350 private static short[] table_scriptFontsMotif;
1351 private static short[] table_alphabeticSuffix;
1352 private static short[] table_stringIDs;
1353 private static char[] table_stringTable;
1354
1355
1356
1357
1358
1359
1360 private static void sanityCheck() {
1361 int errors = 0;
1362
1363
1364
1365 String osName = (String)java.security.AccessController.doPrivileged(
1366 new java.security.PrivilegedAction() {
1367 public Object run() {
1368 return System.getProperty("os.name");
1369 }
1370 });
1371
1372
1373 for (int ii = 1; ii < table_filenames.length; ii++) {
1374 if (table_filenames[ii] == -1) {
1375
1376
1377
1378 if (osName.contains("Windows")) {
1379 System.err.println("\n Error: <filename."
1380 + getString(table_componentFontNameIDs[ii])
1381 + "> entry is missing!!!");
1382 errors++;
1383 } else {
1384 if (verbose && !isEmpty(table_filenames)) {
1385 System.err.println("\n Note: 'filename' entry is undefined for \""
1386 + getString(table_componentFontNameIDs[ii])
1387 + "\"");
1388 }
1389 }
1390 }
1391 }
1392 for (int ii = 0; ii < table_scriptIDs.length; ii++) {
1393 short fid = table_scriptFonts[ii];
1394 if (fid == 0) {
1395 System.out.println("\n Error: <allfonts."
1396 + getString(table_scriptIDs[ii])
1397 + "> entry is missing!!!");
1398 errors++;
1399 continue;
1400 } else if (fid < 0) {
1401 fid = (short)-fid;
1402 for (int iii = 0; iii < NUM_FONTS; iii++) {
1403 for (int iij = 0; iij < NUM_STYLES; iij++) {
1404 int jj = iii * NUM_STYLES + iij;
1405 short ffid = table_scriptFonts[fid + jj];
1406 if (ffid == 0) {
1407 System.err.println("\n Error: <"
1408 + getFontName(iii) + "."
1409 + getStyleName(iij) + "."
1410 + getString(table_scriptIDs[ii])
1411 + "> entry is missing!!!");
1412 errors++;
1413 }
1414 }
1415 }
1416 }
1417 }
1418 if ("SunOS".equals(osName)) {
1419 for (int ii = 0; ii < table_awtfontpaths.length; ii++) {
1420 if (table_awtfontpaths[ii] == 0) {
1421 String script = getString(table_scriptIDs[ii]);
1422 if (script.contains("lucida") ||
1423 script.contains("dingbats") ||
1424 script.contains("symbol")) {
1425 continue;
1426 }
1427 System.err.println("\nError: "
1428 + "<awtfontpath."
1429 + script
1430 + "> entry is missing!!!");
1431 errors++;
1432 }
1433 }
1434 }
1435 if (errors != 0) {
1436 System.err.println("!!THERE ARE " + errors + " ERROR(S) IN "
1437 + "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n");
1438 System.exit(1);
1439 }
1440 }
1441
1442 private static boolean isEmpty(short[] a) {
1443 for (short s : a) {
1444 if (s != -1) {
1445 return false;
1446 }
1447 }
1448 return true;
1449 }
1450
1451
1452 private static void dump() {
1453 System.out.println("\n----Head Table------------");
1454 for (int ii = 0; ii < HEAD_LENGTH; ii++) {
1455 System.out.println(" " + ii + " : " + head[ii]);
1456 }
1457 System.out.println("\n----scriptIDs-------------");
1458 printTable(table_scriptIDs, 0);
1459 System.out.println("\n----scriptFonts----------------");
1460 for (int ii = 0; ii < table_scriptIDs.length; ii++) {
1461 short fid = table_scriptFonts[ii];
1462 if (fid >= 0) {
1463 System.out.println(" allfonts."
1464 + getString(table_scriptIDs[ii])
1465 + "="
1466 + getString(table_componentFontNameIDs[fid]));
1467 }
1468 }
1469 for (int ii = 0; ii < table_scriptIDs.length; ii++) {
1470 short fid = table_scriptFonts[ii];
1471 if (fid < 0) {
1472 fid = (short)-fid;
1473 for (int iii = 0; iii < NUM_FONTS; iii++) {
1474 for (int iij = 0; iij < NUM_STYLES; iij++) {
1475 int jj = iii * NUM_STYLES + iij;
1476 short ffid = table_scriptFonts[fid + jj];
1477 System.out.println(" "
1478 + getFontName(iii) + "."
1479 + getStyleName(iij) + "."
1480 + getString(table_scriptIDs[ii])
1481 + "="
1482 + getString(table_componentFontNameIDs[ffid]));
1483 }
1484 }
1485
1486 }
1487 }
1488 System.out.println("\n----elcIDs----------------");
1489 printTable(table_elcIDs, 0);
1490 System.out.println("\n----sequences-------------");
1491 for (int ii = 0; ii< table_elcIDs.length; ii++) {
1492 System.out.println(" " + ii + "/" + getString((short)table_elcIDs[ii]));
1493 short[] ss = getShortArray(table_sequences[ii * NUM_FONTS + 0]);
1494 for (int jj = 0; jj < ss.length; jj++) {
1495 System.out.println(" " + getString((short)table_scriptIDs[ss[jj]]));
1496 }
1497 }
1498 System.out.println("\n----fontfileNameIDs-------");
1499 printTable(table_fontfileNameIDs, 0);
1500
1501 System.out.println("\n----componentFontNameIDs--");
1502 printTable(table_componentFontNameIDs, 1);
1503 System.out.println("\n----filenames-------------");
1504 for (int ii = 0; ii < table_filenames.length; ii++) {
1505 if (table_filenames[ii] == -1) {
1506 System.out.println(" " + ii + " : null");
1507 } else {
1508 System.out.println(" " + ii + " : "
1509 + getString(table_fontfileNameIDs[table_filenames[ii]]));
1510 }
1511 }
1512 System.out.println("\n----awtfontpaths---------");
1513 for (int ii = 0; ii < table_awtfontpaths.length; ii++) {
1514 System.out.println(" " + getString(table_scriptIDs[ii])
1515 + " : "
1516 + getString(table_awtfontpaths[ii]));
1517 }
1518 System.out.println("\n----proportionals--------");
1519 for (int ii = 0; ii < table_proportionals.length; ii++) {
1520 System.out.println(" "
1521 + getString((short)table_componentFontNameIDs[table_proportionals[ii++]])
1522 + " -> "
1523 + getString((short)table_componentFontNameIDs[table_proportionals[ii]]));
1524 }
1525 int i = 0;
1526 System.out.println("\n----alphabeticSuffix----");
1527 while (i < table_alphabeticSuffix.length) {
1528 System.out.println(" " + getString(table_elcIDs[table_alphabeticSuffix[i++]])
1529 + " -> " + getString(table_alphabeticSuffix[i++]));
1530 }
1531 System.out.println("\n----String Table---------");
1532 System.out.println(" stringID: Num =" + table_stringIDs.length);
1533 System.out.println(" stringTable: Size=" + table_stringTable.length * 2);
1534
1535 System.out.println("\n----fallbackScriptIDs---");
1536 short[] fbsIDs = getShortArray(head[INDEX_fallbackScripts]);
1537 for (int ii = 0; ii < fbsIDs.length; ii++) {
1538 System.out.println(" " + getString(table_scriptIDs[fbsIDs[ii]]));
1539 }
1540 System.out.println("\n----appendedfontpath-----");
1541 System.out.println(" " + getString(head[INDEX_appendedfontpath]));
1542 System.out.println("\n----Version--------------");
1543 System.out.println(" " + getString(head[INDEX_version]));
1544 }
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555 protected static short getComponentFontID(short scriptID, int fontIndex, int styleIndex) {
1556 short fid = table_scriptFonts[scriptID];
1557
1558 if (fid >= 0) {
1559
1560 return fid;
1561 } else {
1562 return table_scriptFonts[-fid + fontIndex * NUM_STYLES + styleIndex];
1563 }
1564 }
1565
1566
1567
1568
1569 protected static short getComponentFontIDMotif(short scriptID, int fontIndex, int styleIndex) {
1570 if (table_scriptFontsMotif.length == 0) {
1571 return 0;
1572 }
1573 short fid = table_scriptFontsMotif[scriptID];
1574 if (fid >= 0) {
1575
1576 return fid;
1577 } else {
1578 return table_scriptFontsMotif[-fid + fontIndex * NUM_STYLES + styleIndex];
1579 }
1580 }
1581
1582 private static int[] getExclusionRanges(short scriptID) {
1583 short exID = table_exclusions[scriptID];
1584 if (exID == 0) {
1585 return EMPTY_INT_ARRAY;
1586 } else {
1587 char[] exChar = getString(exID).toCharArray();
1588 int[] exInt = new int[exChar.length / 2];
1589 int i = 0;
1590 for (int j = 0; j < exInt.length; j++) {
1591 exInt[j] = (exChar[i++] << 16) + (exChar[i++] & 0xffff);
1592 }
1593 return exInt;
1594 }
1595 }
1596
1597 private static boolean contains(short IDs[], short id, int limit) {
1598 for (int i = 0; i < limit; i++) {
1599 if (IDs[i] == id) {
1600 return true;
1601 }
1602 }
1603 return false;
1604 }
1605
1606
1607 protected static String getComponentFontName(short id) {
1608 if (id < 0) {
1609 return null;
1610 }
1611 return getString(table_componentFontNameIDs[id]);
1612 }
1613
1614 private static String getComponentFileName(short id) {
1615 if (id < 0) {
1616 return null;
1617 }
1618 return getString(table_fontfileNameIDs[id]);
1619 }
1620
1621
1622 private static short getComponentFileID(short nameID) {
1623 return table_filenames[nameID];
1624 }
1625
1626 private static String getScriptName(short scriptID) {
1627 return getString(table_scriptIDs[scriptID]);
1628 }
1629
1630 private HashMap<String, Short> reorderScripts;
1631 protected short[] getCoreScripts(int fontIndex) {
1632 short elc = getInitELC();
1633
1634
1635
1636
1637
1638
1639
1640 short[] scripts = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);
1641 if (preferLocaleFonts) {
1642 if (reorderScripts == null) {
1643 reorderScripts = new HashMap<String, Short>();
1644 }
1645 String[] ss = new String[scripts.length];
1646 for (int i = 0; i < ss.length; i++) {
1647 ss[i] = getScriptName(scripts[i]);
1648 reorderScripts.put(ss[i], scripts[i]);
1649 }
1650 reorderSequenceForLocale(ss);
1651 for (int i = 0; i < ss.length; i++) {
1652 scripts[i] = reorderScripts.get(ss[i]);
1653 }
1654 }
1655 return scripts;
1656 }
1657
1658 private static short[] getFallbackScripts() {
1659 return getShortArray(head[INDEX_fallbackScripts]);
1660 }
1661
1662 private static void printTable(short[] list, int start) {
1663 for (int i = start; i < list.length; i++) {
1664 System.out.println(" " + i + " : " + getString(list[i]));
1665 }
1666 }
1667
1668 private static short[] readShortTable(DataInputStream in, int len )
1669 throws IOException {
1670 if (len == 0) {
1671 return EMPTY_SHORT_ARRAY;
1672 }
1673 short[] data = new short[len];
1674 byte[] bb = new byte[len * 2];
1675 in.read(bb);
1676 int i = 0,j = 0;
1677 while (i < len) {
1678 data[i++] = (short)(bb[j++] << 8 | (bb[j++] & 0xff));
1679 }
1680 return data;
1681 }
1682
1683 private static void writeShortTable(DataOutputStream out, short[] data)
1684 throws IOException {
1685 for (short val : data) {
1686 out.writeShort(val);
1687 }
1688 }
1689
1690 private static short[] toList(HashMap<String, Short> map) {
1691 short[] list = new short[map.size()];
1692 Arrays.fill(list, (short) -1);
1693 for (Entry<String, Short> entry : map.entrySet()) {
1694 list[entry.getValue()] = getStringID(entry.getKey());
1695 }
1696 return list;
1697 }
1698
1699
1700 private static String[] stringCache;
1701 protected static String getString(short stringID) {
1702 if (stringID == 0)
1703 return null;
1704
1705
1706
1707
1708
1709
1710
1711 if (stringCache[stringID] == null){
1712 stringCache[stringID] =
1713 new String (table_stringTable,
1714 table_stringIDs[stringID],
1715 table_stringIDs[stringID+1] - table_stringIDs[stringID]);
1716 }
1717 return stringCache[stringID];
1718 }
1719
1720 private static short[] getShortArray(short shortArrayID) {
1721 String s = getString(shortArrayID);
1722 char[] cc = s.toCharArray();
1723 short[] ss = new short[cc.length];
1724 for (int i = 0; i < cc.length; i++) {
1725 ss[i] = (short)(cc[i] & 0xffff);
1726 }
1727 return ss;
1728 }
1729
1730 private static short getStringID(String s) {
1731 if (s == null) {
1732 return (short)0;
1733 }
1734 short pos0 = (short)stringTable.length();
1735 stringTable.append(s);
1736 short pos1 = (short)stringTable.length();
1737
1738 stringIDs[stringIDNum] = pos0;
1739 stringIDs[stringIDNum + 1] = pos1;
1740 stringIDNum++;
1741 if (stringIDNum + 1 >= stringIDs.length) {
1742 short[] tmp = new short[stringIDNum + 1000];
1743 System.arraycopy(stringIDs, 0, tmp, 0, stringIDNum);
1744 stringIDs = tmp;
1745 }
1746 return (short)(stringIDNum - 1);
1747 }
1748
1749 private static short getShortArrayID(short sa[]) {
1750 char[] cc = new char[sa.length];
1751 for (int i = 0; i < sa.length; i ++) {
1752 cc[i] = (char)sa[i];
1753 }
1754 String s = new String(cc);
1755 return getStringID(s);
1756 }
1757
1758
1759 private static final int[] EMPTY_INT_ARRAY = new int[0];
1760 private static final String[] EMPTY_STRING_ARRAY = new String[0];
1761 private static final short[] EMPTY_SHORT_ARRAY = new short[0];
1762 private static final String UNDEFINED_COMPONENT_FONT = "unknown";
1763
1764
1765
1766
1767 static class PropertiesHandler {
1768 public void load(InputStream in) throws IOException {
1769 initLogicalNameStyle();
1770 initHashMaps();
1771 FontProperties fp = new FontProperties();
1772 fp.load(in);
1773 initBinaryTable();
1774 }
1775
1776 private void initBinaryTable() {
1777
1778 head = new short[HEAD_LENGTH];
1779 head[INDEX_scriptIDs] = (short)HEAD_LENGTH;
1780
1781 table_scriptIDs = toList(scriptIDs);
1782
1783
1784
1785
1786
1787
1788 head[INDEX_scriptFonts] = (short)(head[INDEX_scriptIDs] + table_scriptIDs.length);
1789 int len = table_scriptIDs.length + scriptFonts.size() * 20;
1790 table_scriptFonts = new short[len];
1791
1792 for (Entry<Short, Short> entry : scriptAllfonts.entrySet()) {
1793 table_scriptFonts[entry.getKey().intValue()] = entry.getValue();
1794 }
1795 int off = table_scriptIDs.length;
1796 for (Entry<Short, Short[]> entry : scriptFonts.entrySet()) {
1797 table_scriptFonts[entry.getKey().intValue()] = (short)-off;
1798 Short[] v = entry.getValue();
1799 for (int i = 0; i < 20; i++) {
1800 if (v[i] != null) {
1801 table_scriptFonts[off++] = v[i];
1802 } else {
1803 table_scriptFonts[off++] = 0;
1804 }
1805 }
1806 }
1807
1808
1809 head[INDEX_elcIDs] = (short)(head[INDEX_scriptFonts] + table_scriptFonts.length);
1810 table_elcIDs = toList(elcIDs);
1811
1812
1813 head[INDEX_sequences] = (short)(head[INDEX_elcIDs] + table_elcIDs.length);
1814 table_sequences = new short[elcIDs.size() * NUM_FONTS];
1815 for (Entry<Short, short[]> entry : sequences.entrySet()) {
1816
1817 int k = entry.getKey().intValue();
1818 short[] v = entry.getValue();
1819
1820
1821
1822
1823
1824
1825
1826 if (v.length == 1) {
1827
1828 for (int i = 0; i < NUM_FONTS; i++) {
1829 table_sequences[k * NUM_FONTS + i] = v[0];
1830 }
1831 } else {
1832 for (int i = 0; i < NUM_FONTS; i++) {
1833 table_sequences[k * NUM_FONTS + i] = v[i];
1834 }
1835 }
1836 }
1837
1838 head[INDEX_fontfileNameIDs] = (short)(head[INDEX_sequences] + table_sequences.length);
1839 table_fontfileNameIDs = toList(fontfileNameIDs);
1840
1841
1842 head[INDEX_componentFontNameIDs] = (short)(head[INDEX_fontfileNameIDs] + table_fontfileNameIDs.length);
1843 table_componentFontNameIDs = toList(componentFontNameIDs);
1844
1845
1846 head[INDEX_filenames] = (short)(head[INDEX_componentFontNameIDs] + table_componentFontNameIDs.length);
1847 table_filenames = new short[table_componentFontNameIDs.length];
1848 Arrays.fill(table_filenames, (short) -1);
1849
1850 for (Entry<Short, Short> entry : filenames.entrySet()) {
1851 table_filenames[entry.getKey()] = entry.getValue();
1852 }
1853
1854
1855
1856 head[INDEX_awtfontpaths] = (short)(head[INDEX_filenames] + table_filenames.length);
1857 table_awtfontpaths = new short[table_scriptIDs.length];
1858 for (Entry<Short, Short> entry : awtfontpaths.entrySet()) {
1859 table_awtfontpaths[entry.getKey()] = entry.getValue();
1860 }
1861
1862
1863 head[INDEX_exclusions] = (short)(head[INDEX_awtfontpaths] + table_awtfontpaths.length);
1864 table_exclusions = new short[scriptIDs.size()];
1865 for (Entry<Short, int[]> entry : exclusions.entrySet()) {
1866 int[] exI = entry.getValue();
1867 char[] exC = new char[exI.length * 2];
1868 int j = 0;
1869 for (int i = 0; i < exI.length; i++) {
1870 exC[j++] = (char) (exI[i] >> 16);
1871 exC[j++] = (char) (exI[i] & 0xffff);
1872 }
1873 table_exclusions[entry.getKey()] = getStringID(new String (exC));
1874 }
1875
1876 head[INDEX_proportionals] = (short)(head[INDEX_exclusions] + table_exclusions.length);
1877 table_proportionals = new short[proportionals.size() * 2];
1878 int j = 0;
1879 for (Entry<Short, Short> entry : proportionals.entrySet()) {
1880 table_proportionals[j++] = entry.getKey();
1881 table_proportionals[j++] = entry.getValue();
1882 }
1883
1884
1885 head[INDEX_scriptFontsMotif] = (short)(head[INDEX_proportionals] + table_proportionals.length);
1886 if (scriptAllfontsMotif.size() != 0 || scriptFontsMotif.size() != 0) {
1887 len = table_scriptIDs.length + scriptFontsMotif.size() * 20;
1888 table_scriptFontsMotif = new short[len];
1889
1890 for (Entry<Short, Short> entry : scriptAllfontsMotif.entrySet()) {
1891 table_scriptFontsMotif[entry.getKey().intValue()] =
1892 (short)entry.getValue();
1893 }
1894 off = table_scriptIDs.length;
1895 for (Entry<Short, Short[]> entry : scriptFontsMotif.entrySet()) {
1896 table_scriptFontsMotif[entry.getKey().intValue()] = (short)-off;
1897 Short[] v = entry.getValue();
1898 int i = 0;
1899 while (i < 20) {
1900 if (v[i] != null) {
1901 table_scriptFontsMotif[off++] = v[i];
1902 } else {
1903 table_scriptFontsMotif[off++] = 0;
1904 }
1905 i++;
1906 }
1907 }
1908 } else {
1909 table_scriptFontsMotif = EMPTY_SHORT_ARRAY;
1910 }
1911
1912
1913 head[INDEX_alphabeticSuffix] = (short)(head[INDEX_scriptFontsMotif] + table_scriptFontsMotif.length);
1914 table_alphabeticSuffix = new short[alphabeticSuffix.size() * 2];
1915 j = 0;
1916 for (Entry<Short, Short> entry : alphabeticSuffix.entrySet()) {
1917 table_alphabeticSuffix[j++] = entry.getKey();
1918 table_alphabeticSuffix[j++] = entry.getValue();
1919 }
1920
1921
1922 head[INDEX_fallbackScripts] = getShortArrayID(fallbackScriptIDs);
1923
1924
1925 head[INDEX_appendedfontpath] = getStringID(appendedfontpath);
1926
1927
1928 head[INDEX_version] = getStringID(version);
1929
1930
1931 head[INDEX_stringIDs] = (short)(head[INDEX_alphabeticSuffix] + table_alphabeticSuffix.length);
1932 table_stringIDs = new short[stringIDNum + 1];
1933 System.arraycopy(stringIDs, 0, table_stringIDs, 0, stringIDNum + 1);
1934
1935
1936 head[INDEX_stringTable] = (short)(head[INDEX_stringIDs] + stringIDNum + 1);
1937 table_stringTable = stringTable.toString().toCharArray();
1938
1939 head[INDEX_TABLEEND] = (short)(head[INDEX_stringTable] + stringTable.length());
1940
1941
1942 stringCache = new String[table_stringIDs.length];
1943 }
1944
1945
1946 private HashMap<String, Short> scriptIDs;
1947
1948 private HashMap<String, Short> elcIDs;
1949
1950 private HashMap<String, Short> componentFontNameIDs;
1951 private HashMap<String, Short> fontfileNameIDs;
1952 private HashMap<String, Integer> logicalFontIDs;
1953 private HashMap<String, Integer> fontStyleIDs;
1954
1955
1956 private HashMap<Short, Short> filenames;
1957
1958
1959
1960
1961
1962
1963 private HashMap<Short, short[]> sequences;
1964
1965
1966
1967 private HashMap<Short, Short[]> scriptFonts;
1968
1969
1970 private HashMap<Short, Short> scriptAllfonts;
1971
1972
1973 private HashMap<Short, int[]> exclusions;
1974
1975
1976 private HashMap<Short, Short> awtfontpaths;
1977
1978
1979 private HashMap<Short, Short> proportionals;
1980
1981
1982 private HashMap<Short, Short> scriptAllfontsMotif;
1983
1984
1985 private HashMap<Short, Short[]> scriptFontsMotif;
1986
1987
1988 private HashMap<Short, Short> alphabeticSuffix;
1989
1990 private short[] fallbackScriptIDs;
1991 private String version;
1992 private String appendedfontpath;
1993
1994 private void initLogicalNameStyle() {
1995 logicalFontIDs = new HashMap<String, Integer>();
1996 fontStyleIDs = new HashMap<String, Integer>();
1997 logicalFontIDs.put("serif", 0);
1998 logicalFontIDs.put("sansserif", 1);
1999 logicalFontIDs.put("monospaced", 2);
2000 logicalFontIDs.put("dialog", 3);
2001 logicalFontIDs.put("dialoginput",4);
2002 fontStyleIDs.put("plain", 0);
2003 fontStyleIDs.put("bold", 1);
2004 fontStyleIDs.put("italic", 2);
2005 fontStyleIDs.put("bolditalic", 3);
2006 }
2007
2008 private void initHashMaps() {
2009 scriptIDs = new HashMap<String, Short>();
2010 elcIDs = new HashMap<String, Short>();
2011 componentFontNameIDs = new HashMap<String, Short>();
2012
2013
2014
2015 componentFontNameIDs.put("", Short.valueOf((short)0));
2016
2017 fontfileNameIDs = new HashMap<String, Short>();
2018 filenames = new HashMap<Short, Short>();
2019 sequences = new HashMap<Short, short[]>();
2020 scriptFonts = new HashMap<Short, Short[]>();
2021 scriptAllfonts = new HashMap<Short, Short>();
2022 exclusions = new HashMap<Short, int[]>();
2023 awtfontpaths = new HashMap<Short, Short>();
2024 proportionals = new HashMap<Short, Short>();
2025 scriptFontsMotif = new HashMap<Short, Short[]>();
2026 scriptAllfontsMotif = new HashMap<Short, Short>();
2027 alphabeticSuffix = new HashMap<Short, Short>();
2028 fallbackScriptIDs = EMPTY_SHORT_ARRAY;
2029
2030
2031
2032
2033 }
2034
2035 private int[] parseExclusions(String key, String exclusions) {
2036 if (exclusions == null) {
2037 return EMPTY_INT_ARRAY;
2038 }
2039
2040 int numExclusions = 1;
2041 int pos = 0;
2042 while ((pos = exclusions.indexOf(',', pos)) != -1) {
2043 numExclusions++;
2044 pos++;
2045 }
2046 int[] exclusionRanges = new int[numExclusions * 2];
2047 pos = 0;
2048 int newPos = 0;
2049 for (int j = 0; j < numExclusions * 2; ) {
2050 String lower, upper;
2051 int lo = 0, up = 0;
2052 try {
2053 newPos = exclusions.indexOf('-', pos);
2054 lower = exclusions.substring(pos, newPos);
2055 pos = newPos + 1;
2056 newPos = exclusions.indexOf(',', pos);
2057 if (newPos == -1) {
2058 newPos = exclusions.length();
2059 }
2060 upper = exclusions.substring(pos, newPos);
2061 pos = newPos + 1;
2062 int lowerLength = lower.length();
2063 int upperLength = upper.length();
2064 if (lowerLength != 4 && lowerLength != 6
2065 || upperLength != 4 && upperLength != 6) {
2066 throw new Exception();
2067 }
2068 lo = Integer.parseInt(lower, 16);
2069 up = Integer.parseInt(upper, 16);
2070 if (lo > up) {
2071 throw new Exception();
2072 }
2073 } catch (Exception e) {
2074 if (FontUtilities.debugFonts() &&
2075 logger != null) {
2076 logger.config("Failed parsing " + key +
2077 " property of font configuration.");
2078
2079 }
2080 return EMPTY_INT_ARRAY;
2081 }
2082 exclusionRanges[j++] = lo;
2083 exclusionRanges[j++] = up;
2084 }
2085 return exclusionRanges;
2086 }
2087
2088 private Short getID(HashMap<String, Short> map, String key) {
2089 Short ret = map.get(key);
2090 if ( ret == null) {
2091 map.put(key, (short)map.size());
2092 return map.get(key);
2093 }
2094 return ret;
2095 }
2096
2097 class FontProperties extends Properties {
2098 public synchronized Object put(Object k, Object v) {
2099 parseProperty((String)k, (String)v);
2100 return null;
2101 }
2102 }
2103
2104 private void parseProperty(String key, String value) {
2105 if (key.startsWith("filename.")) {
2106
2107
2108 key = key.substring(9);
2109 if (!"MingLiU_HKSCS".equals(key)) {
2110 key = key.replace('_', ' ');
2111 }
2112 Short faceID = getID(componentFontNameIDs, key);
2113 Short fileID = getID(fontfileNameIDs, value);
2114
2115
2116 filenames.put(faceID, fileID);
2117 } else if (key.startsWith("exclusion.")) {
2118 key = key.substring(10);
2119 exclusions.put(getID(scriptIDs,key), parseExclusions(key,value));
2120 } else if (key.startsWith("sequence.")) {
2121 key = key.substring(9);
2122 boolean hasDefault = false;
2123 boolean has1252 = false;
2124
2125
2126 String[] ss = (String[])splitSequence(value).toArray(EMPTY_STRING_ARRAY);
2127 short [] sa = new short[ss.length];
2128 for (int i = 0; i < ss.length; i++) {
2129 if ("alphabetic/default".equals(ss[i])) {
2130
2131 ss[i] = "alphabetic";
2132 hasDefault = true;
2133 } else if ("alphabetic/1252".equals(ss[i])) {
2134
2135 ss[i] = "alphabetic";
2136 has1252 = true;
2137 }
2138 sa[i] = getID(scriptIDs, ss[i]).shortValue();
2139
2140 }
2141
2142 short scriptArrayID = getShortArrayID(sa);
2143 Short elcID = null;
2144 int dot = key.indexOf('.');
2145 if (dot == -1) {
2146 if ("fallback".equals(key)) {
2147 fallbackScriptIDs = sa;
2148 return;
2149 }
2150 if ("allfonts".equals(key)) {
2151 elcID = getID(elcIDs, "NULL.NULL.NULL");
2152 } else {
2153 if (logger != null) {
2154 logger.config("Error sequence def: <sequence." + key + ">");
2155 }
2156 return;
2157 }
2158 } else {
2159 elcID = getID(elcIDs, key.substring(dot + 1));
2160
2161 key = key.substring(0, dot);
2162 }
2163 short[] scriptArrayIDs = null;
2164 if ("allfonts".equals(key)) {
2165 scriptArrayIDs = new short[1];
2166 scriptArrayIDs[0] = scriptArrayID;
2167 } else {
2168 scriptArrayIDs = sequences.get(elcID);
2169 if (scriptArrayIDs == null) {
2170 scriptArrayIDs = new short[5];
2171 }
2172 Integer fid = logicalFontIDs.get(key);
2173 if (fid == null) {
2174 if (logger != null) {
2175 logger.config("Unrecognizable logicfont name " + key);
2176 }
2177 return;
2178 }
2179
2180 scriptArrayIDs[fid.intValue()] = scriptArrayID;
2181 }
2182 sequences.put(elcID, scriptArrayIDs);
2183 if (hasDefault) {
2184 alphabeticSuffix.put(elcID, getStringID("default"));
2185 } else
2186 if (has1252) {
2187 alphabeticSuffix.put(elcID, getStringID("1252"));
2188 }
2189 } else if (key.startsWith("allfonts.")) {
2190 key = key.substring(9);
2191 if (key.endsWith(".motif")) {
2192 key = key.substring(0, key.length() - 6);
2193
2194 scriptAllfontsMotif.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));
2195 } else {
2196 scriptAllfonts.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));
2197 }
2198 } else if (key.startsWith("awtfontpath.")) {
2199 key = key.substring(12);
2200
2201 awtfontpaths.put(getID(scriptIDs, key), getStringID(value));
2202 } else if ("version".equals(key)) {
2203 version = value;
2204 } else if ("appendedfontpath".equals(key)) {
2205 appendedfontpath = value;
2206 } else if (key.startsWith("proportional.")) {
2207 key = key.substring(13).replace('_', ' ');
2208
2209 proportionals.put(getID(componentFontNameIDs, key),
2210 getID(componentFontNameIDs, value));
2211 } else {
2212
2213 int dot1, dot2;
2214 boolean isMotif = false;
2215
2216 dot1 = key.indexOf('.');
2217 if (dot1 == -1) {
2218 if (logger != null) {
2219 logger.config("Failed parsing " + key +
2220 " property of font configuration.");
2221
2222 }
2223 return;
2224 }
2225 dot2 = key.indexOf('.', dot1 + 1);
2226 if (dot2 == -1) {
2227 if (logger != null) {
2228 logger.config("Failed parsing " + key +
2229 " property of font configuration.");
2230
2231 }
2232 return;
2233 }
2234 if (key.endsWith(".motif")) {
2235 key = key.substring(0, key.length() - 6);
2236 isMotif = true;
2237
2238 }
2239 Integer nameID = logicalFontIDs.get(key.substring(0, dot1));
2240 Integer styleID = fontStyleIDs.get(key.substring(dot1+1, dot2));
2241 Short scriptID = getID(scriptIDs, key.substring(dot2 + 1));
2242 if (nameID == null || styleID == null) {
2243 if (logger != null) {
2244 logger.config("unrecognizable logicfont name/style at " + key);
2245 }
2246 return;
2247 }
2248 Short[] pnids;
2249 if (isMotif) {
2250 pnids = scriptFontsMotif.get(scriptID);
2251 } else {
2252 pnids = scriptFonts.get(scriptID);
2253 }
2254 if (pnids == null) {
2255 pnids = new Short[20];
2256 }
2257 pnids[nameID.intValue() * NUM_STYLES + styleID.intValue()]
2258 = getID(componentFontNameIDs, value);
2259
2260
2261
2262
2263
2264 if (isMotif) {
2265 scriptFontsMotif.put(scriptID, pnids);
2266 } else {
2267 scriptFonts.put(scriptID, pnids);
2268 }
2269 }
2270 }
2271 }
2272 }